<template>
  <el-drawer
    v-model="visible"
    title="链路节点"
    size="50%"
    :destroy-on-close="true"
    direction="ltr"
    @open="handleDrawerOpen"
    @close="handleDrawerClose"
  >
    <div class="app-content">
      <div id="container" ref="container"></div>
    </div>
  </el-drawer>

  <!-- 添加节点详情抽屉 -->
  <node-detail-drawer
    v-model="nodeDetailDrawer.visible"
    :node-id="nodeDetailDrawer.nodeId"
  />
</template>

<script setup lang="ts">
import { ref, computed, onMounted, onUnmounted, nextTick } from 'vue'
import { Graph, Cell, Node, Dom } from '@antv/x6'
import dagre from 'dagre'
import insertCss from 'insert-css'
import { ElMessage } from 'element-plus'
import startImage from '../assets/start.png'
import successImage from '../assets/success.png'
import waitingImage from '../assets/waiting.png'
import NodeDetailDrawer from './NodeDetailDrawer.vue'
import { API_URL } from '@/utils/config'

const props = defineProps<{
  modelValue: boolean
  linkId: string | null
}>()

const emit = defineEmits(['update:modelValue'])

const visible = computed({
  get: () => props.modelValue,
  set: (value) => emit('update:modelValue', value)
})

const container = ref<HTMLElement | null>(null)
let graph: Graph | null = null

// 定义样式
insertCss(`
  .x6-cell {
    cursor: default;
  }
  .x6-node .btn {
    cursor: pointer;
  }
`)

// 自定义节点
Graph.registerNode(
  'org-node',
  {
    width: 200,
    height: 70,
    markup: [
      {
        tagName: 'rect',
        attrs: {
          class: 'card',
        },
      },
      {
        tagName: 'text',
        attrs: {
          class: 'rank',
        },
      },
      {
        tagName: 'text',
        attrs: {
          class: 'name',
        },
      },
      {
        tagName: 'text',
        attrs: {
          class: 'level',
        },
      },
    ],
    attrs: {
      '.card': {
        rx: 10,
        ry: 10,
        refWidth: '100%',
        refHeight: '100%',
        fill: '#f5f5f5',
        stroke: '#5F95FF',
        strokeWidth: 1,
        pointerEvents: 'visiblePainted',
        cursor: 'pointer',
        scalable: false,
      },
      '.rank': {
        refX: 20,
        refY: 0.3,
        fill: '#666666',
        fontFamily: 'Arial',
        fontSize: 13,
        textAnchor: 'start',
        textVerticalAnchor: 'middle',
        cursor: 'pointer',
        width: 200,
        scalable: false,
      },
      '.name': {
        refX: 20,
        refY: 0.7,
        fill: '#666666',
        fontFamily: 'Arial',
        fontSize: 13,
        textAnchor: 'start',
        cursor: 'pointer',
        width: 200,
        scalable: false,
      },
      '.level': {
        refX: 0.95,
        refY: 0.5,
        fill: '#666666',
        fontFamily: 'Arial',
        fontSize: 14,
        textAnchor: 'end',
        cursor: 'pointer',
        scalable: false,
      },
    },
  },
  true,
)

// 自定义边
Graph.registerEdge(
  'org-edge',
  {
    zIndex: -1,
    attrs: {
      line: {
        strokeWidth: 2,
        stroke: '#A2B1C3',
        sourceMarker: null,
        targetMarker: null,
      },
    },
  },
  true,
)

// 布局方向
const dir = 'LR' // LR RL TB BT

// 添加节点详情抽屉的状态
const nodeDetailDrawer = ref({
  visible: false,
  nodeId: ''
})

// 监听自定义事件
function setup() {
  if (!graph) return

  graph.on('node:click', ({ node }) => {
    const nodeData = node.getData()
    if (!nodeData.isStart && nodeData.nodeId) {  // 不是开始节点且有 nodeId 才处理
      nodeDetailDrawer.value.nodeId = nodeData.nodeId
      nodeDetailDrawer.value.visible = true
    } else if (nodeData.isStart) {
      ElMessage.warning('开始节点没有内容...')
    } else {
      ElMessage.warning('节点未执行')
    }
  })

  // 保持其他事件处理不变
  graph?.on('node:add', ({ e, node }) => {
    e.stopPropagation()
    const member = createNode(
      'Employee',
      'New Employee',
      Math.random() < 0.5 ? male : female,
    )
    graph?.addCell([member, createEdge(node, member)])
    layout()
  })

  graph?.on('node:delete', ({ e, node }) => {
    e.stopPropagation()
    graph?.removeCell(node)
    layout()
  })
}

// 自动布局
function layout() {
  if (!graph) return
  
  const nodes = graph.getNodes()
  const edges = graph.getEdges()
  const g = new dagre.graphlib.Graph()
  g.setGraph({ 
    rankdir: dir, 
    nodesep: 30,
    ranksep: 50,
    align: 'DL',
    marginx: 20,
    marginy: 20,
  })
  g.setDefaultEdgeLabel(() => ({}))

  const width = 200
  const height = 70
  nodes.forEach((node) => {
    g.setNode(node.id, { width, height })
  })

  edges.forEach((edge) => {
    const source = edge.getSource()
    const target = edge.getTarget()
    if (source.cell && target.cell) {
      g.setEdge(source.cell, target.cell)
    }
  })

  dagre.layout(g)

  g.nodes().forEach((id) => {
    const node = graph.getCellById(id) as Node
    if (node) {
      const pos = g.node(id)
      node.position(pos.x, pos.y)
    }
  })

  edges.forEach((edge) => {
    const source = edge.getSourceNode()!
    const target = edge.getTargetNode()!
    const sourceBBox = source.getBBox()
    const targetBBox = target.getBBox()

    if ((dir === 'LR' || dir === 'RL') && sourceBBox.y !== targetBBox.y) {
      const gap =
        dir === 'LR'
          ? targetBBox.x - sourceBBox.x - sourceBBox.width
          : -sourceBBox.x + targetBBox.x + targetBBox.width
      const fix = dir === 'LR' ? sourceBBox.width : 0
      const x = sourceBBox.x + fix + gap / 2
      edge.setVertices([
        { x, y: sourceBBox.center.y },
        { x, y: targetBBox.center.y },
      ])
    } else if (
      (dir === 'TB' || dir === 'BT') &&
      sourceBBox.x !== targetBBox.x
    ) {
      const gap =
        dir === 'TB'
          ? targetBBox.y - sourceBBox.y - sourceBBox.height
          : -sourceBBox.y + targetBBox.y + targetBBox.height
      const fix = dir === 'TB' ? sourceBBox.height : 0
      const y = sourceBBox.y + fix + gap / 2
      edge.setVertices([
        { x: sourceBBox.center.x, y },
        { x: targetBBox.center.x, y },
      ])
    } else {
      edge.setVertices([])
    }
  })
}

/**
 * 获取节点颜色
 * @param nodeId 节点ID
 * @param isStart 是否是开始节点
 * @param isRecord 是否是执行记录节点
 * @returns 节点颜色
 */
const getColor = (nodeId: string, isStart: boolean, isRecord: boolean) => {
  if (isStart) {
    return '#de2d8c'
  }
  if (nodeId || isRecord) {
    return '#42b983'
  }
  return '#ccc'
}

function createNode(rank: string, name: string, image: string, nodeId: string, level: string, isStart: boolean = false, isRecord: boolean = false) {
  return graph.createNode({
    shape: 'org-node',
    attrs: {
      '.card': {
        fill: getColor(nodeId, isStart, isRecord),
      },
      '.rank': {
        text: Dom.breakText(rank, { width: 150, height: 35 }),
        fill: '#FFF',
        refX: 20,
        refY: 0.3,
        textAnchor: 'start',
      },
      '.name': {
        text: Dom.breakText(name, { width: 150, height: 35 }),
        fill: '#FFF',
        refX: 20,
        refY: 0.7,
        textAnchor: 'start',
      },
      '.level': {
        refX: 0.95,
        refY: 0.5,
        text: level || '-',
        fill: level === 'ERROR' ? 'yellow' : '#42b983',
      },
    },
    data: {
      nodeId,
      isStart,
    },
  })
}

function createEdge(source: Cell, target: Cell) {
  return graph.createEdge({
    shape: 'org-edge',
    source: { cell: source.id },
    target: { cell: target.id },
  })
}

// 初始化图表
const initGraph = () => {
  if (!container.value) return
  
  // 如果已存在图表实例，先销毁
  if (graph) {
    graph.dispose()
    graph = null
  }
  
  graph = new Graph({
    container: container.value,
    interacting: false,
    panning: true,
    mousewheel: false,
    connecting: {
      anchor: 'center',
      connector: 'rounded',
      connectionPoint: 'anchor',
    },
    grid: {
      visible: true,
      type: 'dot',
      size: 20,
    },
    scaling: {
      min: 1,
      max: 1,
    },
    autoResize: true,
    padding: {
      top: 40,
      right: 40,
      bottom: 40,
      left: 40,
    },
  })
  
  graph.centerContent()
  
  setup()
}

// 添加抽屉关闭处理函数
const handleDrawerClose = () => {
  if (graph) {
    graph.dispose()
    graph = null
  }
}

// 修改 handleDrawerOpen 函数
const handleDrawerOpen = async () => {
  if (!props.linkId) return
  
  try {
    // 确保图表已初始化
    await nextTick()
    initGraph() // 每次打开都重新初始化
    
    let nodes = []
    let edges = []
    
    const response = await fetch(`${API_URL}/logs/link/${props.linkId}`)
    const data = await response.json()

    // Create start node
    // 获取链路名称
    const linkName = data.data.link_name
    const startNode = createNode(linkName, 'Start', '', '', '', true)
    nodes.push(startNode)

    if (data.code === 0 && data.data?.content) {
      let nodeIndex = 1
      // Iterate through each method type
      for (const [methodName, records] of Object.entries(data.data.content)) {
        if (records.length === 0) {
          // Create waiting node for unexecuted methods
          const waitNode = createNode(methodName, '未执行', '', '', '')
          nodes.push(waitNode)
          edges.push(createEdge(startNode, waitNode))
          nodeIndex++
        } else if (records.length === 1) {
          // For single record, create direct node
          const item = records[0]
          const singleNode = createNode(
            item.MethodName,
            item.CreatedAt,
            '',
            item.NodeId,
            item.Level
          )
          nodes.push(singleNode)
          edges.push(createEdge(startNode, singleNode))
          nodeIndex++
        } else {
          // Create parent node for multiple records
          const parentNode = createNode(methodName, '执行记录', '', '', '', false, true)
          nodes.push(parentNode)
          edges.push(createEdge(startNode, parentNode))
          nodeIndex++

          // Create child nodes for each record
          records.forEach((item: any) => {
            const childNode = createNode(
              item.MethodName,
              item.CreatedAt,
              '',
              item.NodeId,
              item.Level
            )
            nodes.push(childNode)
            edges.push(createEdge(parentNode, childNode))
            nodeIndex++
          })
        }
      }
    } else {
      ElMessage.error('获取链路流程图失败')
    }

    // 添加所有节点和边
    graph?.resetCells([...nodes, ...edges])
    
    // 执行布局
    layout()
    
    // 调整视图
    graph?.centerContent()

  } catch (error) {
    console.error('获取链路流程图失败:', error)
    ElMessage.error('获取链路流程图失败')
  }
}

// 组件卸载时清理
onUnmounted(() => {
  if (graph) {
    graph.dispose()
    graph = null
  }
})

</script>

<style scoped>
.app-content {
  height: calc(100vh - 120px);
  padding: 10px;
  background: #fff;
}

#container {
  height: 100%;
  border: 1px solid #ddd;
  border-radius: 4px;
  background: #fff;
  position: relative;
}

/* 添加一些辅助样式 */
:deep(.x6-graph) {
  background: #fff !important;
}

:deep(.x6-graph-scroller) {
  background: #fff !important;
}
</style>